package com.zhou.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 通用自然日工具类
 * @author lang.zhou
 * @date 2018-12-14
 */
public class DateUtil {
    /*private static ThreadLocal<SimpleDateFormat> format=new ThreadLocal<>();
    private static SimpleDateFormat getFormat(){
        if(format.get()==null){
            format.set(new SimpleDateFormat("yyyyMMdd"));
        }
        return format.get();
    }*/
    /*public static void main(String[] args){
        DateUtil.getDayInMonth(20181209,1);
        DateUtil.getDayInQuarter(20181209,120);
        DateUtil.getDayInYear(20181209,120);
    }*/

    /**
     * 将字符型或Date对象转换成整型，yyyyMMdd格式
     * @return yyyyMMdd
     */
    private static int parseObject(Object date){
        if(date instanceof Integer){
            return (Integer) date;
        }else if(date instanceof String){
            return Integer.parseInt(((String)date).replaceAll("-","").replaceAll("/",""));
        }else if(date instanceof Date){
            return Integer.parseInt(new SimpleDateFormat("yyyyMMdd").format(date));
        }
        return 0;
    }
    private static Calendar getCalendar(Object dateObj){
        Calendar calendar = Calendar.getInstance();
        int date=parseObject(dateObj);
        calendar.set(date/10000, date%10000/100-1, date%100);
        return calendar;
    }
    /**
     * 获取第前n天，n为负数时表示后n天，n为0表示当天
     * @param dateObj：可以输入整型、字符串或Date对象。格式为20180926 或"2018-09-26" 或"2018/09/26"
     */
    public static String getLastDay(Object dateObj,int n,String format){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.DATE, -n);
        return new SimpleDateFormat(format).format(calendar.getTime());
    }
    public static String getLastDay(Object dateObj,int n){
        return getLastDay(dateObj, n,"yyyyMMdd");
    }
    public static Date getLastDayDate(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.DATE, -n);
        return calendar.getTime();
    }
    /**
     * 获取date所在周的前n周最后一天，n为负数时表示后n周，n为0表示本周
     * @param dateObj：格式为20180926
     */
    public static String getLastDayOfWeek(Object dateObj,int n) {
        Calendar calendar = getCalendar(dateObj);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);//将每周第一天设为星期一，默认是星期天
        calendar.add(Calendar.DATE, -1*7*n);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }
    /**
     * 获取date所在周的前n周第一天，n为负数时表示后n周，n为0表示本周
     * @param dateObj：格式为20180926
     */
    public static String getFirstDayOfWeek(Object dateObj,int n) {
        Calendar calendar = getCalendar(dateObj);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);//将每周第一天设为星期一，默认是星期天
        calendar.add(Calendar.DATE, -1*7*n);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }
    /**
     * 获取date所在月的第前n个月的最后一天，n为负数时表示后n个月，n为0表示本月
     */
    public static String getLastDayOfMonth(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.MONTH, -n+1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.DATE, -1);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }
    /**
     * 获取date所在月的第前n个月的第一天，n为负数时表示后n个月，n为0表示本月
     */
    public static String getFirstDayOfMonth(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.MONTH, -n);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }
    /**
     * 获取date所在季度的前n个季度的最后一天，n为负数时表示后n个季度，n为0表示本季度
     * @param dateObj：格式为20180926
     */
    public static String getLastDayOfQuarter(Object dateObj,int n){
        Calendar c=Calendar.getInstance();
        int date=parseObject(dateObj);
        int monthSet=date%10000/100-1;
        c.set(date/10000, monthSet, date%100);
        int month=monthSet+1;
        c.add(Calendar.MONTH,-n*3+1);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.DATE, -1);
        c.add(Calendar.MONTH, 3-(month%3==0 ? 3 : month%3));
        return new SimpleDateFormat("yyyyMMdd").format(c.getTime());
    }
    /**
     * 获取date所在季度的前n个季度的第一天，n为负数时表示后n个季度，n为0表示本季度
     * @param dateObj：格式为20180926
     */
    public static String getFirstDayOfQuarter(Object dateObj,int n){
        Calendar c=Calendar.getInstance();
        int date=parseObject(dateObj);
        int monthSet=date%10000/100-1;
        c.set(date/10000, monthSet, date%100);
        int month=monthSet+1;
        c.add(Calendar.MONTH,-n*3);
        c.set(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.MONTH, 1-(month%3==0 ? 3 : month%3));
        return new SimpleDateFormat("yyyyMMdd").format(c.getTime());
    }
    /**
     * 获取date所在年的前n年的最后一天，n为负数时表示后n年，n为0表示本年
     * @param dateObj：格式为20180926
     */
    public static String getLastDayOfYear(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.YEAR, -n+1);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.add(Calendar.DATE, -1);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }
    /**
     * 获取date所在年的前n年的第一天，n为负数时表示后n年，n为0表示本年
     * @param dateObj：格式为20180926
     */
    public static String getFirstDayOfYear(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        calendar.add(Calendar.YEAR, -n);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        return new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
    }

    /**
     * 获取两个日期间的天数
     */
    public static int getBetweenDay(Object date1_,Object date2_){
        int date1=parseObject(date1_);
        int date2=parseObject(date2_);
        Calendar calendar = Calendar.getInstance();
        calendar.set(date1/10000, date1%10000/100-1, date1%100);
        long a=calendar.getTimeInMillis();
        calendar.set(date2/10000, date2%10000/100-1, date2%100);
        long b=calendar.getTimeInMillis();
        double betweenDays = (((b - a) * 1.0) / (1000 * 60 * 60 * 24)) + 0.5;
        return (int) Math.floor(betweenDays);
    }

    /**
     * 获取两个日期所间隔的周数
     */
    private static int getBetweenWeek(Object date1,Object date2){
        int d1=Integer.parseInt(getFirstDayOfWeek(date1,0));
        int d2=Integer.parseInt(getFirstDayOfWeek(date2,0));
        long daten=getBetweenDay(d1,d2);
        return (int)(daten/7);
    }

    /**
     * 获取两个日期所在月数的差值
     */
    public static int getBetweenMonth(Object date1_,Object date2_){
        int date1=parseObject(date1_);
        int date2=parseObject(date2_);
        int year1=date1/10000;
        int year2=date2/10000;
        int month1=date1%10000/100;
        int month2=date2%10000/100;
        if(month2<month1){
            month2+=12;
            year2--;
        }
        return (year2-year1)*12+month2-month1;
    }
    /**
     * 获取两个日期所在季度数的差值
     */
    public static int getBetweenQuarter(Object date1,Object date2){
        return getBetweenMonth(getFirstDayOfQuarter(date1,0),getFirstDayOfQuarter(date2,0))/3;
    }
    /**
     * 获取两个日期所在年数的差值
     */
    public static int getBetweenYear(Object date1,Object date2){
        return parseObject(date1)/10000-parseObject(date2)/10000;
    }
    /**
     * 获取date在本年的周数
     */
    public static int getWeekInYear(Object dateObj){
        Calendar calendar = getCalendar(dateObj);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }
    /**
     * 获取date在本月的周数
     */
    public static int getWeekInMonth(Object dateObj){
        Calendar calendar = getCalendar(dateObj);
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        return calendar.get(Calendar.WEEK_OF_MONTH);
    }
    /**
     * 获取date是本星期中的第几天
     * @return 返回1~7
     */
    public static int getDayInWeek(Object dateObj){
        Calendar calendar = getCalendar(dateObj);
        int dayOfWeek=calendar.get(Calendar.DAY_OF_WEEK);
        return dayOfWeek!=1 ? dayOfWeek-1 : 7;
    }

    /**
     * 获取dateObj所在月的第n天，若超出本月天数，返回本月最后一天
     */
    public static String getDayInMonth(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        n=n>0 ? n :32;
        if(n>calendar.getActualMaximum(Calendar.DAY_OF_MONTH)){
            return getLastDayOfMonth(dateObj,0);
        }
        return getLastDay(getFirstDayOfMonth(dateObj,0),1-n);
    }

    /**
     * 获取dateObj所在周的第n天，若超出本周天数，返回本周最后一天
     */
    public static String getDayInWeek(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        n=n>0 ? n :32;
        if(n>calendar.getActualMaximum(Calendar.DAY_OF_WEEK)){
            return getLastDayOfWeek(dateObj,0);
        }
        return getLastDay(getFirstDayOfWeek(dateObj,0),1-n);
    }
    public static String getWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (1 == dayOfWeek) {
            return "周日";
        } else if (2 == dayOfWeek) {
            return "周一";
        } else if (3 == dayOfWeek) {
            return "周二";
        } else if (4 == dayOfWeek) {
            return "周三";
        } else if (5 == dayOfWeek) {
            return "周四";
        } else if (6 == dayOfWeek) {
            return "周五";
        } else {
            return 7 == dayOfWeek ? "周六" : "";
        }
    }
    /**
     * 获取dateObj所在季度的第n天，若超出本季度天数，返回本季度最后一天
     */
    public static String getDayInQuarter(Object dateObj,int n){
        String fir = getFirstDayOfQuarter(dateObj,0);
        String las = getLastDayOfQuarter(dateObj,0);
        String now = getLastDay(fir,1-n);
        int d = parseObject(now);
        if(d > parseObject(las)){
            return las;
        }
        return now;
    }
    /**
     * 获取dateObj所在年的第n天，若超出本年天数，返回本年最后一天
     */
    public static String getDayInYear(Object dateObj,int n){
        Calendar calendar = getCalendar(dateObj);
        n=n>0 ? n :32;
        if(n>calendar.getActualMaximum(Calendar.DAY_OF_YEAR)){
            return getLastDayOfYear(dateObj,0);
        }
        return getLastDay(getFirstDayOfYear(dateObj,0),1-n);
    }
    public static int getQuarterInYear(Object dateObj){
        int month=parseObject(dateObj)%10000/100;
        if(month>=1 && month<=3){
            return 1;
        }else if(month>3 && month<=6){
            return 2;
        }else if(month>6 && month<=9){
            return 3;
        }else if(month>9 && month<=12){
            return 4;
        }
        return 0;
    }
}
